///<reference types="../../types/easyui" />

import { IGenerate } from '../igenerate';
import { GenerateOption } from '../generateOption';
import { EasyuiHelper } from './easyuiHelper';
import { relation } from './optionAndMethodsRelation';
import { getDepend } from './depends';
import { unique, CONSTKEY, getTemplate } from '../utils';
import { IExecute, ExecuteProivder } from '../methodExceuteProvider'; 
import { DefaultGenerate } from '../defaultGenerate';
import {ExtendBind} from './extendbind';

export class EasyuiGenerate extends DefaultGenerate {

    /**
     * easyui对象
     */
    public easyui:any;

    /**
     * jquery对象
     */
    public jquery:JQueryStatic;

    /**
     * 获取执行方法的提供者
     */
    public executeProvider:IExecute;

    /**
     * 监听列表
     */
    private computeds:Array<any>;

    /**
     * 扩展处理
     */
    private extendBind:ExtendBind;

    constructor(option:GenerateOption){ 
        super(option);
        this.jquery = option.jquery;
        this.easyui = this.jquery.parser;
        this.executeProvider = new ExecuteProivder(option);
        this.extendBind=new ExtendBind(option);
        this.registerPlugins();
    }

    /**
     * 组件easyui的相关组件
     */
    registerPlugins(){
        //fix easyui defaults
        //1. datagrid missing columns, frozenColumns;
        this.jquery.fn.datagrid.defaults.columns = [[]];
        this.jquery.fn.datagrid.defaults.frozenColumns = [[]];

        //extends panel default event.
        this._extendPanelEvent();

        let plugins = this.easyui.plugins;
        //动态生成一个function的类
        plugins.forEach(pluginName => {
            let defaults = this.jquery.fn[pluginName].defaults;
            let methods = this.jquery.fn[pluginName].methods;
            let deps = getDepend(pluginName);
            if(defaults){
                //options必须要是独立的，事件（放原型上），方法可以原型链上的
                let props = Object.getOwnPropertyNames(defaults);
                //方法
                let methodKeys = Object.getOwnPropertyNames(methods);
                if(deps){
                    deps.forEach(dep=>{
                        let depMethods = this.jquery.fn[dep].methods;
                        methodKeys = methodKeys.concat(Object.getOwnPropertyNames(depMethods));
                    });
                    methodKeys = unique(methodKeys);
                }
                this.option.ko.components.register(`${CONSTKEY.CompPrefix}${pluginName}`,{
                    template: getTemplate(pluginName),
                    viewModel: EasyuiHelper.createEasyui(pluginName, props, methodKeys, this.executeProvider, this.extendBind)
                });
            }
        });
    }

    generate(componentName: string, params: any, viewModel: any):any {
        let first = true, that = this;

        this._touchMount(componentName, params, viewModel);
        //获取监控数据列表
        let observableKeys = this._getObservableKeys(params);

        //配置参数存在，就进行监听
        if(params.options){ 
            //监听params的变化变化
            ko.computed(function(){
                
                let changeObs = that._getChangeObservable(params,observableKeys,viewModel);

                if(first){ //如果是初始化执行，后面的业务不用重复执行了
                    first = false;
                    return;
                }
                if(changeObs.changeOpts.length>0){
                    that._touchPaint(componentName, params, viewModel, changeObs,function(){
                        if(changeObs.changeOpts.length == changeObs.reflows.length){//说明配置的改变，可能通过方法操作完成
                            changeObs.reflows.forEach(item=>{
                                viewModel[item.methodName](item.val);
                            });
                        }else{
                            //引起了组件重绘
                            viewModel.repaint(params.options);
                        }
                    });
                }
            });
        }

        return viewModel;
    }

    /**
     * 获取有变更的监控对象列表
     * @param params 配置对象
     * @param observableKeys 可监控的参数列表key
     * @param viewModel 视图数据对象
     * @return 
     * {
     *  changeOpts：存在变更的对象列表
     *  reflows：可以使用回流操作来处理的变更列表
     * }
     */
    _getChangeObservable(params:any, observableKeys:Array<string>, viewModel:any):any{
        let opts = params.options; 
        let changeOpts = new Array<any>();
        let reflows = new Array<any>(); //可以通过方法来进行配置改变的参数
        observableKeys.forEach(key => {
            let param = opts[key];
            let tmp = ko.unwrap(param);
            //探测监控对象有变化的属性，区分那些可以用方法进行改变，那些需要重绘
            if(ko.isObservable(param) && param.hasChanged()){
                changeOpts.push(param);
                if(relation[viewModel.name] && relation[viewModel.name][key]){
                    reflows.push({
                        val: tmp,
                        methodName: relation[viewModel.name][key]
                    });
                }
            }
        });
        return {
            changeOpts: changeOpts,
            reflows: reflows
        }
    }

    /**
     * modify:2018-06-05 sam dragon, 重写panel的onOpen方法，用于panel内容的组件解析
     */
    _extendPanelEvent(){
        $.fn.panel.defaults.onOpen = function(){
            debugger;
        }
    }
}